[org 0x1000]

mov si, load_msg
call print

; 获取物理内存大小
get_mem_size:
    xor ebx, ebx
    mov edx, 0x534D4150
    mov di, ards_buffer

.next:
    mov eax, 0xe820
    mov ecx, 20
    int 0x15
    jc error ; 出错

    add di, cx
    inc word [ards_count]
    cmp ebx, 0
    jnz .next

; 开启保护模式
protect_mode:
    mov dx ,0x92 ; 开启 A20 线
    in al, dx
    or al, 0b10
    out dx, al

    cli

    lgdt [gdt_ptr] ; 加载 gdt

    mov eax ,cr0 ; 打开 PE 位
    or eax, 0b1
    mov cr0, eax

    jmp dword selector_code:protect_entry ; 刷新流水线 进入保护模式

print:
    mov ah ,0x0e
.next:
    mov al, [si]
    cmp al, 0
    jz .done
    int 0x10
    inc si
    jmp .next
.done:
    ret

error:
    mov si, .msg
    call print
    hlt
    jmp $
    .msg:
        db "Loading ERROR!!!",10,13,0

[bits 32]
protect_entry:
    mov ax, selector_data
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

    ; 读取 kernel
    mov ecx, 10
    mov bl, 200
    mov edi, 0x10000
    call read_disk

    mov esp, 0x10000
    mov eax, 0x20231208 ; 魔数
    mov ebx, ards_count

    ; 跳转到 kernel
    jmp selector_code:0x10000

read_disk:
    mov dx, 0x1f2 ; 传入读取扇区数量
    mov al, bl
    out dx, al

    ; 传入 LBA 编号
    inc dx
    mov al, cl
    out dx, al

    inc dx
    shr ecx, 8
    mov al, cl
    out dx, al

    inc dx
    shr ecx, 8
    mov al, cl
    out dx, al

    inc dx
    shr ecx, 8
    mov al, cl
    and al, 0b0000_1111

    ; 设置模式
    or al, 0b1110_0000
    out dx, al

    ; 输入读硬盘命令
    inc dx
    mov al, 0x20
    out dx, al

    xor ecx, ecx
    mov cl, bl
.read:
    call .wait
    call .reads
    loop .read

    ret

; 等待硬盘
.wait:
    mov dx, 0x1f7
.next:
    jmp $ + 2
    jmp $ + 2
    jmp $ + 2
    in al, dx
    and al, 0b1000_1000
    cmp al, 0b0000_1000
    jnz .next

    ret

.reads:
    mov dx, 0x1f0
    push cx
    mov cx, 256
.loop:
    in ax, dx
    mov word [edi], ax
    add edi, 2
    loop .loop

    pop cx
    ret

selector_code equ (1 << 3)
selector_data equ (2  << 3)

gdt_ptr:
    dw (gdt_end - gdt_base) - 1 ; gdt 界限
    dd gdt_base ; gdt 基址

gdt_base:
    dd 0,0 ; NULL 描述符

; dpl 为 0 的代码段
; base : 0x00000000
; limit : 0xFFFFFFFF
gdt_code:
    dw 0xFFFF
    dw 0
    db 0
    db 0b1_00_1_1010
    db 0b1_1_0_0_1111
    db 0
; dpl 为 0 的数据段
; base : 0x00000000
; limit : 0xFFFFFFFF
gdt_data:
    dw 0xFFFF
    dw 0
    db 0
    db 0b1_00_1_0010
    db 0b1_1_0_0_1111
    db 0
gdt_end:

load_msg:
    db "Loading LucnxOS...",10,13,0

magic:
    dd 0x20231208
ards_count:
    dd 0
ards_buffer: